﻿using System.Collections.Generic;
using System.Threading;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace Chimp.Core
{
    public class ChimpScene : ChimpBase
    {
        public static ChimpTexture2D FBTex;
        public JobSceneManager J_SceneManager;
        public ChimpTexture2D[] LayerFB;
        public List<List<ChimpPostFX>> LayerFX;
        public Mutex ObjectLock = new Mutex();
        ~ChimpScene ( )
        {
            J_SceneManager.T.Abort();
            foreach (var j in J_SceneManager.Jobs)
            {
                j.T.Abort();

            }
            J_SceneManager.Jobs.Clear();



        }

        public ChimpScene(int layers)
        {
            ObjectList = new List<ChimpBase>();
            ObjectMap = new Dictionary<string, ChimpBase>();
            LightList = new List<ChimpLight>();
            RtFB = new ChimpRenderTarget();
            TxFB = new ChimpTexture2D((int) ChimpApp.W, (int) ChimpApp.H);
            PostFXList = new List<ChimpPostFX>();
            ViewPos = new Vector2();
            ViewZoom = 1.0f;
            ViewRotation = 0.0f;
            FBTex = TxFB;
            J_SceneManager = new JobSceneManager(this, 4);
            LayerCount = layers;
        }

        public List<ChimpLight> LightList { get; set; }
        public List<ChimpBase> ObjectList { get; set; }
        public Dictionary<string, ChimpBase> ObjectMap { get; set; }
        public ChimpRenderTarget RtFB { get; set; }
        public ChimpTexture2D TxFB { get; set; }
        public List<ChimpPostFX> PostFXList { get; set; }
        public Vector2 ViewPos { get; set; }
        public float ViewZoom { get; set; }
        public float ViewRotation { get; set; }
        public int LayerCount { get; set; }

        public void SetView(float x, float y)
        {
            ViewPos = new Vector2(x, y);
        }

        public void AddLight(ChimpLight l)
        {
            LightList.Add(l);
            AddObj(l);
        }

        public void AddPostFX(int layer, ChimpPostFX fx)
        {
            layer--;
            PostFXList.Add(fx);
            fx.LayerID = layer;
            fx.Scene = this;
        }

        public void RemovePostFX(ChimpPostFX fx)
        {
            PostFXList.Remove(fx);
            fx.Scene = null;
        }

        public void RemoveLight(ChimpLight l)
        {
            LightList.Remove(l);
            RemoveObj(l);
        }

        public void RemoveLight(string id)
        {
            ChimpBase l = ObjectMap[id];
            LightList.Remove(l as ChimpLight);
            RemoveObj(l);
        }

        public void AddObj(ChimpBase obj)
        {
            ObjectList.Add(obj);
            if (obj.ID == null)
            {
                obj.ID = "";
            }
            if (ObjectMap.ContainsKey(obj.ID))
            {
                ObjectMap.Remove(obj.ID);
            }
            ObjectMap.Add(obj.ID, obj);
            obj.Scene = this;
        }

        public void RemoveObj(ChimpBase obj)
        {
            ObjectLock.WaitOne();
            ObjectList.Remove(obj);
            ObjectLock.ReleaseMutex();
            obj.Scene = null;
        }

        public void RemoveObj(string id)
        {
            ChimpBase obj = ObjectMap[id];
            ObjectList.Remove(obj);
            ObjectMap.Remove(obj.ID);
            obj.Scene = null;
        }

        public override bool OnUpdate(Vector2 pos)
        {
            return false;
            int i = 0;
            while (i < ObjectList.Count)
            {
                i++;
            }
        }

        public void UpdateObject(ChimpBase o)
        {
            //if (i >= ObjectList.Count) return;

            PrepObj(ref o);

            o.Update(-ViewPos);
        }

        private static Vector2 FinObj(ChimpBase o, float lr, float ls, Vector2 op)
        {
            //  o.Rotation = lr;
            //  o.Scale = ls;
            //  o.Rotation = lr;


            return op;
        }

        public float GetLevelAt(Vector2 pos, string id, int layerid)
        {
            float r = 0.0f;
            foreach (ChimpBase o in ObjectList)
            {
                float l = o.GetLevel(id);

                Vector2 mp = pos;
                Vector2 dir = mp - o.Pos;
                float dis = dir.Length;

                dis = dis/o.GetRange(id);
                dis = (1.0f - dis) < 0 ? 0.0f : (1.0f - dis);
                l *= dis;
                r += l;
            }
            return r;
        }

        private void PrepObj(ref ChimpBase o)
        {
            float vr = ViewRotation, vz = ViewZoom;

            o.DrawScale = o.Scale*vz;
            o.DrawRotation = vr + o.Rotation;

            Vector2 np = (o.Pos - ViewPos) - ChimpApp.Mid;


            np = ChimpMath.Rotate(ref np, ref vr);
            o.DrawPos = ChimpApp.Mid + ChimpMath.Scale(ref np, ref vz);
        }

        public void Draw()
        {
            while (true)
            {
                J_SceneManager.Lock();
                if (J_SceneManager.UpdateDone)
                {
                    J_SceneManager.UpdateDone = false;
                    J_SceneManager.Release();
                    break;
                }
                J_SceneManager.Release();
            }

            foreach(var o in ObjectList){
                o.Prerender(Vector2.Zero);
            }
            foreach ( ChimpPostFX p in PostFXList )
            {
               p.OnPreRender();
            }

            var mid = new Vector2(ChimpApp.W/2.0f, ChimpApp.H/2.0f);
            //  RtFB.AttachTexture(TxFB);
            RtFB.Bind();

            RtFB.AttachTexture(TxFB);

            GL.Clear(ClearBufferMask.ColorBufferBit);
            for (int l = 0; l < LayerCount; l++)
            {
                int i = 0;
                while (i < ObjectList.Count)
                {
                    if (ObjectList[i].LayerID == l)
                    {
                        ObjectList[i].Draw(-ViewPos);
                    }
                    i++;
                }
            }
            ChimpUI.RenderUI();
            RtFB.Unbind();

            if (PostFXList.Count == 0)
            {
                ChimpDraw.BlendMode = ChimpBlend.Lighten;
                ChimpDraw.Image(new Vector4(0, 0, ChimpApp.W, ChimpApp.H), TxFB, new Vector4(1, 1, 1, 1));
            }
            else
            {
                ChimpTexture2D src = TxFB;
                foreach (ChimpPostFX p in PostFXList)
                {
                    src = p.Render(src);
                }
                ChimpDraw.BlendMode = ChimpBlend.Lighten;
                ChimpDraw.Image(new Vector4(0, 0, ChimpApp.W, ChimpApp.H), src, new Vector4(1, 1, 1, 1));
            }

            J_SceneManager.Lock();
            J_SceneManager.PerformUpdate = true;
            J_SceneManager.Release();
        }
    }
}